package com.shamar.blog.web.frontend;

import java.util.*;
import javax.mail.Message;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;

import com.shamar.blog.dto.*;
import com.shamar.blog.entity.*;
import com.shamar.blog.enums.BlogUserStateEnum;
import com.shamar.blog.enums.UserEmailStateEnum;
import com.shamar.blog.exceptions.UserEmailOperationException;
import com.shamar.blog.service.BlogCategoryService;
import com.shamar.blog.service.BlogContentService;
import com.shamar.blog.service.BlogLabelService;
import com.shamar.blog.service.BlogUserService;
import com.shamar.blog.util.CodeUtil;
import com.shamar.blog.util.HttpServletRequestUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.ModelAndView;

import java.util.regex.*;

import javax.servlet.http.HttpServletRequest;

/**
 * @author shamarfang
 * @date 2020-08-02 13:09
 * @desc 首页控制器
 */
@Controller
@RequestMapping("/community")
public class IndexController {
	Logger logger = LoggerFactory.getLogger(IndexController.class);

	@Autowired
	private BlogUserService blogUserService;
	@Autowired
	private BlogContentService blogContentService;
	@Autowired
	private BlogCategoryService blogCategoryService;
	@Autowired
	private BlogLabelService blogLabelService;
	/**
	 * 首页页面
	 * @param request
	 * @return
	 */
	@GetMapping(value = "/index")
	public ModelAndView index(HttpServletRequest request){
		// 定义返回值
		ModelAndView  model  =  new ModelAndView("frontend/index");
		// 获取所有的分类
        BlogCategoryExecution blogCategoryExecution = blogCategoryService.getAllCategory();
        List<BlogCategory> allCategory = blogCategoryExecution.getBlogCategoryList();
		// 获取最近的博文列表
		BlogContentExecution latestBlogContentExecution = blogContentService.getIndexContent(1);
		List<BlogContent> latestBlogContentList = latestBlogContentExecution.getBlogContentList();
        int contenSize = latestBlogContentList.size();
        int categorysize = allCategory.size();
        //给每一篇博文加上类别名
        for(int i=contenSize-1;i>=0;i--){
            for (int j= categorysize-1;j>=0;j--){
            //若博文的categoryid和类别的id相等,则赋上类别名
            if(latestBlogContentList.get(i).getCategoryId().equals(allCategory.get(j).getId())){
                latestBlogContentList.get(i).setCategoryName(allCategory.get(j).getCategoryName());
            }}
        }
		if (contenSize > 0){
			model.addObject("latestContentList",latestBlogContentList);
		}
//		最近发表博文处理完毕 处理最受欢迎博文
		BlogContentExecution mostFavoriteBlogContentExecution = blogContentService.getIndexContent(2);
        List<BlogContent> mostfavoriteContentList = mostFavoriteBlogContentExecution.getBlogContentList();
        int favoritecontensize = mostfavoriteContentList.size();
        //        给每一篇博文加上类别名
        for(int i=favoritecontensize-1;i>=0;i--){
            for (int j= categorysize-1;j>=0;j--){
                //若博文的categoryid和类别的id相等,则赋上类别名
                if(mostfavoriteContentList.get(i).getCategoryId().equals(allCategory.get(j).getId())){
                    mostfavoriteContentList.get(i).setCategoryName(allCategory.get(j).getCategoryName());
                }}
        }
		if (favoritecontensize>0){
			model.addObject("mostfavoriteblogContentList",mostfavoriteContentList);
		}
		/**
		 * 查询标签名
		 */
		BlogLabelExecution  blogLabelExecution = blogLabelService.getBlogLabelListByCount(0,40);
		if (blogLabelExecution.getBlogLabelList()!=null){
			model.addObject("BlogLabelList",blogLabelExecution.getBlogLabelList());
		}
		return model;
	}

	@GetMapping(value = "/articles_list")
	private ModelAndView articlesList(HttpServletRequest request){
		//定义返回值
		ModelAndView  model  =  new ModelAndView("frontend/articles-list");
		//获取所有的分类
		BlogCategoryExecution blogCategoryExecution = blogCategoryService.getAllCategory();
		List<BlogCategory> allCategory = blogCategoryExecution.getBlogCategoryList();
		int categorySize = allCategory.size();
		model.addObject("allCategory",allCategory);
		//构建一个空的查询条件
		BlogContent blogContent = new BlogContent();
		//设置条件为已发布
		blogContent.setStatus(1);
		//获取排序方式
		int orderParam = HttpServletRequestUtil.getInt(request, "o");
		orderParam = orderParam==-1 ? 2: orderParam;
		//获取页数,每页6条记录
		int page = HttpServletRequestUtil.getInt(request,"p");
		int cid = HttpServletRequestUtil.getInt(request,"cid");
		//获得搜索的关键字
		String keyword = HttpServletRequestUtil.getString(request,"s");
		model.addObject("current_page", page);
		//处理最近发布的博文
		if (orderParam == 1) {
			BlogContentExecution latestBlogContentExecution = blogContentService.selectByBlogContentConditionPagination(blogContent, "pushtime", "DESC", page>1? (page-1)*5:0,5);
			List<BlogContent> latestBlogContentList = latestBlogContentExecution.getBlogContentList();
			int contenSize = latestBlogContentList.size();
			//        给每一篇博文加上类别名
			for (int i = contenSize - 1; i >= 0; i--) {
				for (int j = categorySize - 1; j >= 0; j--) {
                //若博文的categoryid和类别的id相等,则赋上类别名
					if (latestBlogContentList.get(i).getCategoryId().equals(allCategory.get(j).getId())) {
						latestBlogContentList.get(i).setCategoryName(allCategory.get(j).getCategoryName());
					}
				}
			}
			//取出前100个字符
			for (int i = contenSize - 1; i >= 0; i--){
				if (latestBlogContentList.get(i).getContent()!=null&&latestBlogContentList.get(i).getContent().length()>100) {
					String tempStr = latestBlogContentList.get(i).getContent().substring(0, 100);
					latestBlogContentList.get(i).setContent(tempStr);
				}
			}
			if (contenSize > 0) {
				model.addObject("ContentList", latestBlogContentList);
			}
			return model;
		}
		//处理搜索
		else if (Objects.nonNull(keyword)) {
			BlogContent keyBlogContent = new BlogContent();
			keyBlogContent.setContent(keyword);
			keyBlogContent.setStatus(1);
			BlogContentExecution keywordBlogContentExecution = blogContentService.selectByBlogContentConditionPagination(keyBlogContent,null,null,page>1? (page-1)*5:0,5);
			List<BlogContent> keyBlogContentList = keywordBlogContentExecution.getBlogContentList();
			int contenSize = keyBlogContentList.size();
			//        给每一篇博文加上类别名
			for (int i = contenSize - 1; i >= 0; i--) {
				for (int j = categorySize - 1; j >= 0; j--) {
//                若博文的categoryid和类别的id相等,则赋上类别名
					if (keyBlogContentList.get(i).getCategoryId().equals(allCategory.get(j).getId())) {
						keyBlogContentList.get(i).setCategoryName(allCategory.get(j).getCategoryName());
					}
				}
			}
			//取出前100个字符
			for (int i = contenSize - 1; i >= 0; i--){
				if (keyBlogContentList.get(i).getContent()!=null&&keyBlogContentList.get(i).getContent().length()>100) {
					String tempStr = keyBlogContentList.get(i).getContent().substring(0, 100);
					keyBlogContentList.get(i).setContent(tempStr);
				}
			}
			if (contenSize > 0) {
				model.addObject("ContentList", keyBlogContentList);
			}
			return model;
		}
		//处理分类列表
		else if (cid != -1 &&cid != 0) {
			BlogContent blogContentByCategory = new BlogContent();
			//按分类id查找
			blogContentByCategory.setCategoryId(cid);
            blogContentByCategory.setStatus(1);
			BlogContentExecution blogContentByCategoryExecution = blogContentService.selectByBlogContentConditionPagination(blogContentByCategory,null,null,page>1? (page-1)*5:0,5);
			List<BlogContent> blogContentByCategoryList = blogContentByCategoryExecution.getBlogContentList();
			int contenSize = blogContentByCategoryList.size();
			//        给每一篇博文加上类别名
			for (int i = contenSize - 1; i >= 0; i--) {
				for (int j = categorySize - 1; j >= 0; j--) {
                //若博文的categoryid和类别的id相等,则赋上类别名
					if (blogContentByCategoryList.get(i).getCategoryId().equals(allCategory.get(j).getId())) {
						blogContentByCategoryList.get(i).setCategoryName(allCategory.get(j).getCategoryName());
					}
				}
			}
			//取出前100个字符
			for (int i = contenSize - 1; i >= 0; i--){
				if (blogContentByCategoryList.get(i).getContent()!=null && blogContentByCategoryList.get(i).getContent().length()>100) {
					String tempStr = blogContentByCategoryList.get(i).getContent().substring(0, 100);
					blogContentByCategoryList.get(i).setContent(tempStr);
				}
			}
			if (contenSize > 0) {
				model.addObject("ContentList", blogContentByCategoryList);
			}
			return model;
		}
		//处理最热博文
		else if (orderParam == 2) {
			BlogContentExecution latestBlogContentExecution = blogContentService.selectByBlogContentConditionPagination(blogContent,"star_count","DESC",page>1? (page-1)*5:0,5);
			List<BlogContent> favoriteBlogContentList = latestBlogContentExecution.getBlogContentList();
			int contenSize = favoriteBlogContentList.size();
			//        给每一篇博文加上类别名
			for (int i = contenSize - 1; i >= 0; i--) {
				for (int j = categorySize - 1; j >= 0; j--) {
//                若博文的categoryid和类别的id相等,则赋上类别名
					if (favoriteBlogContentList.get(i).getCategoryId().equals(allCategory.get(j).getId())) {
						favoriteBlogContentList.get(i).setCategoryName(allCategory.get(j).getCategoryName());
					}
				}
			}
			//取出前100个字符
			for (int i = contenSize - 1; i >= 0; i--){
				if (favoriteBlogContentList.get(i).getContent()!=null && favoriteBlogContentList.get(i).getContent().length()>100) {
					String tempStr = favoriteBlogContentList.get(i).getContent().substring(0, 100);
					favoriteBlogContentList.get(i).setContent(tempStr);
				}
			}
			if (contenSize > 0) {
				model.addObject("ContentList", favoriteBlogContentList);
			}
		}
//		处理我的博文
		else if (orderParam == 3) {
			BlogContent myBlogContent = new BlogContent();
//			暂定用户id为1
			try{
			BlogUser blogUser = (BlogUser) request.getSession().getAttribute("currentBlogUser");
			Integer uid = blogUser.getId();
			myBlogContent.setUserId(uid);
			}catch (Exception e){
//				myBlogContent.setUserId(1);
				return model;
			}
			BlogContentExecution latestBlogContentExecution = blogContentService.selectByBlogContentConditionPagination(myBlogContent,"Id",null,page>1? (page-1)*5:0,5);
			List<BlogContent> myBlogContentList = latestBlogContentExecution.getBlogContentList();
			int contenSize = myBlogContentList.size();
			//        给每一篇博文加上类别名
			for (int i = contenSize - 1; i >= 0; i--) {
				for (int j = categorySize - 1; j >= 0; j--) {
//                若博文的categoryid和类别的id相等,则赋上类别名
					if (myBlogContentList.get(i).getCategoryId().equals(allCategory.get(j).getId())) {
						myBlogContentList.get(i).setCategoryName(allCategory.get(j).getCategoryName());
					}
				}
			}
			//取出前100个字符
			for (int i = contenSize - 1; i >= 0; i--){
				if (myBlogContentList.get(i).getContent()!=null && myBlogContentList.get(i).getContent().length()>100) {
					String tempStr = myBlogContentList.get(i).getContent().substring(0, 100);
					myBlogContentList.get(i).setContent(tempStr);
				}
			}
			if (contenSize > 0) {
				model.addObject("ContentList", myBlogContentList);
			}
			return model;
		}
		return model;
	}


	@GetMapping(value ="contactUs")
    @ResponseBody
    public ModelAndView contactUs(HttpServletRequest request){
        //定义返回值
		return new ModelAndView("frontend/contact");
    }

    @GetMapping(value ="Faq")
    @ResponseBody
    private ModelAndView faq(HttpServletRequest request){
        //定义返回值
		return new ModelAndView("frontend/faq");
    }

	/**
	 * 用户找回密码界面
	 * @param request
	 * @return
	 */
	@GetMapping(value = "/forgetpwd")
	private ModelAndView forgetPwd(HttpServletRequest request){
		//定义返回值
		return new ModelAndView("frontend/forgetpwd");
	}

	/**
	 * 生成重置密码链接并发送邮件
	 * @param request
	 * @return
	 */
	@PostMapping(value = "/send_email")
	@ResponseBody
	private Map<String,Object> sendEmail(HttpServletRequest request){
		//这里是jackson处理post请求带json数据时的方式
	//private Map<String,Object> send_email(@RequestBody UserEmail userEmail){
		//定义返回值
		Map<String,Object> modelMap = new HashMap<>();
		if (!CodeUtil.checkVerifyCode(request)) {
			modelMap.put("success", false);
			modelMap.put("errMsg", "验证码输入错误");
			return modelMap;
		}
		//注意replaceAll前面的是正则表达式
		//生成随机字符串,用于校验
		String uuid = UUID.randomUUID().toString().replaceAll("-","");
		//通过formdata传输数据
		String email = HttpServletRequestUtil.getString(request, "email");
		if (Objects.isNull(email)) {
			modelMap.put("success", false);
			modelMap.put("errMsg", "邮箱不能是空的!");
			return modelMap;
		}
		//后端也进行一遍检查
		if((Pattern.matches("\\w+@(\\w+.)+[a-z]{2,3}",email))) {
			logger.info("这是一个有效邮箱地址：{}", email);
		} else {
			modelMap.put("success",false);
			modelMap.put("errMsg", "邮箱格式不正确");
		}
		UserEmail userEmail = new UserEmail();
		userEmail.setSendType("forget");
		userEmail.setCode(uuid);
		userEmail.setEmail(email);
		//在调用插入数据库dao之前必须要先校验当前email是否已在找回状态中
		try{
			UserEmail checkUseremail = new UserEmail();
			checkUseremail.setEmail(email);
			UserEmailExecution flag = blogUserService.getUserEmailByCondition(checkUseremail);
			if (flag.getState() != UserEmailStateEnum.NO_CODE.getState()){
				//如果数据库中存在记录,返回已经在找回状态,请查看邮箱
				modelMap.put("success", false);
				modelMap.put("errMsg", "当前账号已经在找回状态,请查看邮箱");
				return modelMap;
			}
			UserEmailExecution userEmailExecution = blogUserService.addUserEmail(userEmail);
			if (userEmailExecution.getState() == UserEmailStateEnum.NORMAL.getState()){
				//插入数据库成功
				Properties properties = new Properties();
				// 连接协议
				properties.put("mail.transport.protocol", "smtp");
				// 主机名
				properties.put("mail.smtp.host", "smtp.qq.com");
				// 端口号
				properties.put("mail.smtp.port", 465);
				properties.put("mail.smtp.auth", "true");
				// 设置是否使用ssl安全连接 ---一般都使用
				properties.put("mail.smtp.ssl.enable", "true");
				// 设置是否显示debug信息 true 会在控制台显示相关信息
				properties.put("mail.debug", "true");
				// 得到会话对象
				Session session = Session.getInstance(properties);
				// 获取邮件对象
				Message message = new MimeMessage(session);
				// 设置发件人邮箱地址
				message.setFrom(new InternetAddress("register_for_code@foxmail.com"));
				// 设置收件人邮箱地址
				message.setRecipients(Message.RecipientType.TO, new InternetAddress[]{new InternetAddress(email)});
				// 设置邮件标题
				message.setSubject("程序员博客社区找回密码链接");
				// 设置邮件内容
				message.setText("请在15分钟内点击以下链接进行密码重置__http://localhost/community/resetpwd?code=".concat(userEmail.getCode()));
				// 得到邮差对象
				Transport transport = session.getTransport();
				// 连接自己的邮箱账户 密码为QQ邮箱开通stmp服务后得到的客户端授权码
				transport.connect("register_for_code@foxmail.com", "zxfdfjyouvbsghec");
				// 发送邮件
				transport.sendMessage(message, message.getAllRecipients());
				transport.close();
				modelMap.put("success", true);
			}else {
				modelMap.put("success", false);
				modelMap.put("errMsg", userEmailExecution.getStateInfo());
			}
		}catch (Exception e) {
			modelMap.put("success", false);
			modelMap.put("errMsg", e.getMessage());
		}
		modelMap.put("email",email);
		return modelMap;
	}

	/**
	 * 重置密码页面
	 * @param request
	 * @return
	 */
	@GetMapping(value = "/resetpwd")
	public ModelAndView resetPwd(HttpServletRequest request){
		try{
        String code = HttpServletRequestUtil.getString(request, "code");
        UserEmail userEmail = new UserEmail(code);
        UserEmailExecution userEmailExecution = blogUserService.getUserEmailByCondition(userEmail);
		if (userEmailExecution.getState() == UserEmailStateEnum.NORMAL.getState()){
			ModelAndView  model  =  new ModelAndView("frontend/resetpwd");
			//数据库能查到记录,说明在找回密码流程中
			model.addObject("email",userEmailExecution.getUserEmail());
			model.addObject("code",code);
			return model;
		}else{
			ModelAndView  model  =  new ModelAndView("frontend/resetpwd_404");
			String errorString = "链接已失效,请重新获取";
			model.addObject("errorString", errorString);
			return model;
		}
		}catch (Exception e){
			return new ModelAndView("404");
		}
	}

	@PostMapping(value = "/do_reset_pwd")
	@ResponseBody
	public Map<String,Object> doResetPwd(HttpServletRequest request){
		Map<String,Object> modelMap = new HashMap<>();
		if (!CodeUtil.checkVerifyCode(request)) {
			modelMap.put("success", false);
			modelMap.put("errMsg", "验证码输入错误");
			return modelMap;
		}
		String code = HttpServletRequestUtil.getString(request, "code");
		String email = HttpServletRequestUtil.getString(request, "email");
		String password = HttpServletRequestUtil.getString(request, "password");
		if (Objects.isNull(code) || Objects.isNull(email) || Objects.isNull(password)) {
			modelMap.put("success", false);
			modelMap.put("errMsg", "参数错误!");
			return modelMap;
		}
		try{
			//根据传来的code获得邮箱
			UserEmail userEmail = new UserEmail();
			userEmail.setCode(code);
			UserEmailExecution userEmailExecution = blogUserService.getUserEmailByCondition(userEmail);
			if (userEmailExecution.getState() != UserEmailStateEnum.NORMAL.getState()){
				modelMap.put("success", false);
				modelMap.put("errMsg", "数据库忙,请稍后重试");
				return modelMap;
			}
			//比对获取到的email和传来的是否一致,防止用户删除readonly篡改邮箱号
			if (!email.equals(userEmailExecution.getUserEmail().getEmail())){
				modelMap.put("success", false);
				modelMap.put("errMsg", "邮箱错误,请检查!");
				return modelMap;
			}
			//如果都通过检查,进行更改密码操作
			BlogUser blogUser = new BlogUser();
			blogUser.setEmail(email);
			BlogUserExecution blogUserExecution = blogUserService.getBlogUserByCondition(blogUser, 0,100);
			if (blogUserExecution.getState() == BlogUserStateEnum.NORMAL.getState()){
				//能取到用户数据
				Integer id = blogUserExecution.getBlogUser().getId();
				BlogUser updateBlogUser = new BlogUser(id);
				updateBlogUser.setPassword(password);
				Integer updateFlag = blogUserService.updateBlogUser(updateBlogUser);
				if (updateFlag == 1){
					//修改成功, 删除存储code和email对应关系的记录,即整个找回密码流程到此结束
					try{
						Integer deleteFlag = blogUserService.deleteUserEmail(userEmailExecution.getUserEmail());
						//删除对应关系成功
						if (deleteFlag == 1) {
							modelMap.put("success", true);
							return modelMap;
						} else {
							//删除失败,应该进行回滚操作,后面再添加,当前告诉用户重新点击链接输入密码
							modelMap.put("success", false);
							modelMap.put("errMsg", "处理失败,请回到邮箱重新点击链接再试一次");
						}
					}catch (UserEmailOperationException e){
						modelMap.put("success", false);
						modelMap.put("errMsg", e.getMessage());
					}
				}else {
					modelMap.put("success", false);
					modelMap.put("errMsg", "服务器内部错误,请稍后再试");
				}

			}else {
				modelMap.put("success", false);
				modelMap.put("errMsg", "服务器内部错误,请稍后再试");
				return modelMap;
			}


		}catch (Exception e){
			logger.error(e.getMessage());
			modelMap.put("success", false);
			modelMap.put("errMsg", e.getMessage());
			return modelMap;
		}

		return modelMap;
	}
}
